import 'dart:io';
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as path;
import 'package:gal/gal.dart';

/// FLV/HLS 流视频下载服务
class FlvDownloadService {
  final Map<String, CancelToken> _cancelTokens = {};
  final Map<String, double> _downloadProgress = {};

  /// 下载流视频（FLV/HLS）
  Future<void> downloadStream({
    required String streamUrl,
    required String deviceName,
    required String startTime,
    required String endTime,
    required String duration,
    required Function(
      double progress,
      String speed,
      String downloadedSize,
      String totalSize,
    )
    onProgress,
    required Function(String filePath, String fileName) onComplete,
    required Function(String error) onError,
  }) async {
    CancelToken? cancelToken;

    try {
      // 生成文件名和路径
      final fileName = _generateFileName(deviceName, startTime, endTime);
      final downloadDir = await _getDownloadDirectory();
      final outputPath = path.join(downloadDir, fileName);

      print('🎬 FLV流视频下载开始: $deviceName');
      print('📁 流地址: $streamUrl');
      print('📁 保存路径: $outputPath');

      // 创建取消令牌
      cancelToken = CancelToken();
      _cancelTokens[streamUrl] = cancelToken;

      // 开始下载流视频
      await _downloadStreamFile(
        streamUrl: streamUrl,
        outputPath: outputPath,
        cancelToken: cancelToken,
        onProgress: onProgress,
        onComplete: (filePath) async {
          // 额外保存到公共目录
          await _saveToPublicDirectory(filePath);
          onComplete(filePath, fileName);
        },
        onError: onError,
      );
    } catch (e) {
      print('❌ FLV流视频下载失败: $e');
      onError(e.toString());
    } finally {
      // 清理资源
      if (cancelToken != null) {
        _cancelTokens.remove(streamUrl);
      }
    }
  }

  /// 下载流文件（使用流式处理）
  Future<void> _downloadStreamFile({
    required String streamUrl,
    required String outputPath,
    required CancelToken cancelToken,
    required Function(
      double progress,
      String speed,
      String downloadedSize,
      String totalSize,
    )
    onProgress,
    required Function(String filePath) onComplete,
    required Function(String error) onError,
  }) async {
    IOSink? fileSink;

    try {
      int downloadedBytes = 0;
      final startTime = DateTime.now();
      DateTime? lastProgressUpdate;

      // 配置Dio
      final dio = Dio();
      dio.options.connectTimeout = Duration(seconds: 30);
      dio.options.receiveTimeout = Duration(minutes: 30);
      dio.options.sendTimeout = Duration(seconds: 30);

      // 设置请求头
      dio.options.headers = {
        'User-Agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
        'Accept': '*/*',
        'Connection': 'keep-alive',
      };

      print('🔍 开始下载流视频（流式处理）:');
      print('  URL: $streamUrl');
      print('  保存路径: $outputPath');

      // 打开文件准备写入
      final file = File(outputPath);
      fileSink = file.openWrite();

      // 使用流式请求
      final response = await dio.get<ResponseBody>(
        streamUrl,
        cancelToken: cancelToken,
        options: Options(
          responseType: ResponseType.stream,
          receiveTimeout: Duration(minutes: 30),
        ),
      );

      if (response.statusCode != 200) {
        throw Exception('HTTP错误: ${response.statusCode}');
      }

      print('✅ 流连接已建立，开始接收数据...');

      // 获取总大小（如果有的话）
      final contentLengthList = response.data?.headers['content-length'];
      final contentLength =
          contentLengthList != null && contentLengthList.isNotEmpty
              ? contentLengthList.first
              : null;
      final totalBytes =
          contentLength != null ? int.tryParse(contentLength) : null;

      if (totalBytes != null) {
        print('📊 文件总大小: ${_formatBytes(totalBytes)}');
      } else {
        print('📊 文件总大小: 未知（流式传输）');
      }

      // 逐块读取并写入
      await for (final chunk in response.data!.stream) {
        // 检查是否取消
        if (cancelToken.isCancelled) {
          print('⏸️ 流下载已被取消');
          break;
        }

        // 写入数据
        fileSink.add(chunk);
        downloadedBytes += chunk.length;

        // 计算进度
        final progress =
            totalBytes != null ? downloadedBytes / totalBytes : 0.0;
        final elapsed = DateTime.now().difference(startTime).inSeconds;
        final speed = elapsed > 0 ? downloadedBytes / elapsed : 0;

        // 更新进度（防抖：每秒最多更新一次）
        final now = DateTime.now();
        if (lastProgressUpdate == null ||
            now.difference(lastProgressUpdate).inSeconds >= 1) {
          _downloadProgress[streamUrl] = progress;

          onProgress(
            progress,
            '${_formatBytes(speed.toInt())}/s',
            _formatBytes(downloadedBytes),
            totalBytes != null ? _formatBytes(totalBytes) : '未知',
          );

          lastProgressUpdate = now;
        }
      }

      // 关闭文件
      await fileSink.flush();
      await fileSink.close();
      fileSink = null;

      // 检查下载是否被取消
      if (cancelToken.isCancelled) {
        print('❌ 流下载被取消，删除临时文件');
        if (await file.exists()) {
          await file.delete();
        }
        return;
      }

      // 验证文件
      if (!await file.exists()) {
        throw Exception('下载的文件不存在');
      }

      final fileSize = await file.length();
      if (fileSize < 1024) {
        print('❌ 下载的文件大小异常: ${_formatBytes(fileSize)}');
        throw Exception('下载的文件大小异常，可能不是有效的视频文件');
      }

      print('✅ 流视频下载完成');
      print('📁 文件大小: ${_formatBytes(fileSize)}');
      print(
        '📁 下载速度: ${_formatBytes((fileSize / DateTime.now().difference(startTime).inSeconds).toInt())}/s',
      );

      // 最后一次进度更新（100%）
      onProgress(1.0, '0B/s', _formatBytes(fileSize), _formatBytes(fileSize));

      // 额外保存一份到公共下载目录
      await _saveToPublicDirectory(outputPath);

      // 额外保存一份到相册
      await _saveToAlbum(outputPath);

      onComplete(outputPath);
    } catch (e) {
      // 确保关闭文件
      if (fileSink != null) {
        try {
          await fileSink.close();
        } catch (_) {}
      }

      if (e is DioException && e.type == DioExceptionType.cancel) {
        print('⏸️ 流下载被用户取消');
      } else {
        print('❌ 流视频下载失败: $e');
        onError(e.toString());
      }

      // 删除不完整的文件
      try {
        final file = File(outputPath);
        if (await file.exists()) {
          await file.delete();
          print('🗑️ 已删除不完整的文件');
        }
      } catch (_) {}
    }
  }

  /// 取消下载
  void cancelDownload(String streamUrl) {
    print('❌ 取消流下载: $streamUrl');

    final cancelToken = _cancelTokens[streamUrl];
    if (cancelToken != null && !cancelToken.isCancelled) {
      cancelToken.cancel('用户取消下载');
    }

    _cancelTokens.remove(streamUrl);
    _downloadProgress.remove(streamUrl);

    print('✅ 流下载已取消: $streamUrl');
  }

  /// 获取下载目录（内部存储）
  Future<String> _getDownloadDirectory() async {
    final directory = await getApplicationDocumentsDirectory();
    final downloadDir = Directory('${directory.path}/downloads');
    if (!await downloadDir.exists()) {
      await downloadDir.create(recursive: true);
    }
    print('📁 使用内部存储下载目录: ${downloadDir.path}');
    return downloadDir.path;
  }

  /// 生成文件名（确保唯一性）
  String _generateFileName(
    String deviceName,
    String startTime,
    String endTime,
  ) {
    try {
      // 解析时间字符串
      DateTime startDateTime = DateTime.parse(startTime);
      DateTime endDateTime = DateTime.parse(endTime);

      // 格式化为北京时间：MM月DD日 HH:mm
      String startFormatted =
          '${startDateTime.month.toString().padLeft(2, '0')}月${startDateTime.day.toString().padLeft(2, '0')}日 ${startDateTime.hour.toString().padLeft(2, '0')}:${startDateTime.minute.toString().padLeft(2, '0')}';
      String endFormatted =
          '${endDateTime.hour.toString().padLeft(2, '0')}:${endDateTime.minute.toString().padLeft(2, '0')}';

      // 清理设备名称
      final sanitizedDeviceName = deviceName.replaceAll(
        RegExp(r'[^\w\s-]'),
        '',
      );

      // 添加时间戳确保文件名唯一性
      final timestamp = DateTime.now().millisecondsSinceEpoch;

      // 生成文件名（使用.mp4扩展名，因为转换后的视频格式）
      if (startDateTime.year == endDateTime.year &&
          startDateTime.month == endDateTime.month &&
          startDateTime.day == endDateTime.day) {
        return '${timestamp}_${sanitizedDeviceName}_${startFormatted}-${endFormatted}.mp4';
      } else {
        String endDateFormatted =
            '${endDateTime.month.toString().padLeft(2, '0')}月${endDateTime.day.toString().padLeft(2, '0')}日 ${endDateTime.hour.toString().padLeft(2, '0')}:${endDateTime.minute.toString().padLeft(2, '0')}';
        return '${timestamp}_${sanitizedDeviceName}_${startFormatted}-${endDateFormatted}.mp4';
      }
    } catch (e) {
      print('⚠️ 时间解析失败，使用原始格式: $e');
      final startTimeFormatted = startTime.replaceAll('T', ' ').split('.')[0];
      final endTimeFormatted = endTime.replaceAll('T', ' ').split('.')[0];
      final sanitizedDeviceName = deviceName.replaceAll(
        RegExp(r'[^\w\s-]'),
        '',
      );
      final timestamp = DateTime.now().millisecondsSinceEpoch;
      return '${timestamp}_${sanitizedDeviceName}_${startTimeFormatted}-${endTimeFormatted}.mp4';
    }
  }

  /// 格式化字节数
  String _formatBytes(int bytes) {
    if (bytes < 1024) return '${bytes}B';
    if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(1)}KB';
    if (bytes < 1024 * 1024 * 1024)
      return '${(bytes / (1024 * 1024)).toStringAsFixed(1)}MB';
    return '${(bytes / (1024 * 1024 * 1024)).toStringAsFixed(1)}GB';
  }

  /// 额外保存文件到公共目录
  Future<void> _saveToPublicDirectory(String filePath) async {
    try {
      print('📁 开始额外保存流视频到公共下载目录...');

      final file = File(filePath);
      if (!await file.exists()) {
        print('⚠️ 文件不存在，跳过公共目录保存: $filePath');
        return;
      }

      // 检查gal权限
      final hasAccess = await Gal.hasAccess(toAlbum: false);
      if (!hasAccess) {
        print('🔑 请求存储权限...');
        final requestResult = await Gal.requestAccess(toAlbum: false);
        if (!requestResult) {
          print('❌ 存储权限被拒绝，跳过公共目录保存');
          return;
        }
      }

      print('✅ 存储权限检查通过');

      // 使用Gal保存视频文件到公共下载目录
      await Gal.putVideo(filePath);
      print('✅ 流视频已额外保存到公共下载目录');
    } on GalException catch (e) {
      print('💥 Gal插件异常: ${e.type.message}');
      print('⚠️ 公共目录保存失败，但内部存储文件正常');
    } catch (e) {
      print('❌ 公共目录保存失败: $e');
      print('⚠️ 内部存储文件正常，用户仍可通过应用播放');
    }
  }

  /// 额外保存文件到相册
  Future<void> _saveToAlbum(String filePath) async {
    try {
      print('📸 开始额外保存流视频到相册...');

      final file = File(filePath);
      if (!await file.exists()) {
        print('⚠️ 文件不存在，跳过相册保存: $filePath');
        return;
      }

      // 验证文件大小
      final fileSize = await file.length();
      if (fileSize < 1024) {
        print('⚠️ 文件大小异常，跳过相册保存: ${_formatBytes(fileSize)}');
        return;
      }

      // 检查gal权限（相册权限）
      final hasAccess = await Gal.hasAccess(toAlbum: true);
      if (!hasAccess) {
        print('🔑 请求相册权限...');
        final requestResult = await Gal.requestAccess(toAlbum: true);
        if (!requestResult) {
          print('❌ 相册权限被拒绝，跳过相册保存');
          return;
        }
      }

      print('✅ 相册权限检查通过');

      // 使用Gal保存视频文件到相册
      // 注意：Gal.putVideo 在请求相册权限后会保存到相册
      await Gal.putVideo(filePath);
      print('✅ 流视频已额外保存到相册');
      print('📸 用户可在相册中找到该视频文件');
    } on GalException catch (e) {
      print('💥 Gal插件异常: ${e.type.message}');
      print('⚠️ 相册保存失败，但内部存储文件正常');
    } catch (e) {
      print('❌ 相册保存失败: $e');
      print('⚠️ 内部存储文件正常，用户仍可通过应用播放');
    }
  }

  /// 获取下载进度
  double getProgress(String streamUrl) {
    return _downloadProgress[streamUrl] ?? 0.0;
  }

  /// 清理所有下载
  void dispose() {
    for (final cancelToken in _cancelTokens.values) {
      if (!cancelToken.isCancelled) {
        cancelToken.cancel('服务关闭');
      }
    }
    _cancelTokens.clear();
    _downloadProgress.clear();
  }
}
